package org.sraosha.framework.util;

import lombok.SneakyThrows;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class FileUtil {

    private static final int DEFAULT_BUFFER_SIZE = 1024;

    //将文件转换成Byte数组
    public static byte[] getBytesByFile(String pathStr) {
        File file = new File(pathStr);
        try (FileInputStream fis = new FileInputStream(file);
             ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            byte[] b = new byte[1000];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            byte[] data = bos.toByteArray();
            return data;
        } catch (Exception e) {
            e.printStackTrace();
//            LOGGER.error(MessageFormat.format("文件转换异常: {0}", e.getMessage()), e);
        }
        return null;
    }

    /**
     * 获得指定文件的byte数组
     *
     * @param filePath 文件绝对路径
     * @return
     */
    public static byte[] file2Byte(String filePath) {
        ByteArrayOutputStream bos = null;
        FileInputStream fis = null;
        BufferedInputStream in = null;
        try {
            File file = new File(filePath);

            if (!file.exists()) {
                throw new FileNotFoundException("file not exists");
            }

            bos = new ByteArrayOutputStream((int) file.length());
            fis = new FileInputStream(file);
            in = new BufferedInputStream(fis);

            int buf_size = 1024;

            byte[] buffer = new byte[buf_size];

            int len = 0;

            while (-1 != (len = in.read(buffer, 0, buf_size))) {
                bos.write(buffer, 0, len);
            }

            return bos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
//            LOGGER.error(MessageFormat.format("获取文件异常: {0}", e.getMessage()), e);
            return null;
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
                if (fis != null) {
                    fis.close();
                }
                if (bos != null) {
                    bos.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
//                LOGGER.error(MessageFormat.format("获取文件异常: {0}", e.getMessage()), e);
            }
        }
    }


    //将Byte数组转换成文件
    public static void getFileByBytes(byte[] bytes, String filePath, String fileName) {
        File file = new File(filePath + "\\" + fileName);
        if (!file.exists()) {
            (new File(file.getParent())).mkdirs();
        }
        try (FileOutputStream fos = new FileOutputStream(file);
             BufferedOutputStream bos = new BufferedOutputStream(fos)
        ) {
            File dir = new File(filePath);
            // 判断文件目录是否存在
            if (!dir.exists() && dir.isDirectory()) {
                dir.mkdirs();
            }
            bos.write(bytes);
        } catch (Exception e) {
            e.printStackTrace();
//            LOGGER.error(MessageFormat.format("转换文件异常: {0}", e.getMessage()), e);
        }
    }


    /**
     * 将字符串写入指定文件(当指定的父路径中文件夹不存在时，会最大限度去创建，以保证保存成功！)
     *
     * @param res      原字符串
     * @param filePath 文件路径
     */
    public static void string2File(String res, String filePath) {
        File distFile = new File(filePath);
        if (!distFile.exists()) {
            try {
                distFile.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
//                LOGGER.error(MessageFormat.format("创建文件异常: {0}", e.getMessage()), e);
            }
        }
        try (BufferedReader bufferedReader = new BufferedReader(new StringReader(res));
             BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(distFile))) {
            if (!distFile.getParentFile().exists())
                distFile.getParentFile().mkdirs();
            //字符缓冲区
            char buf[] = new char[DEFAULT_BUFFER_SIZE];
            int len;
            while ((len = bufferedReader.read(buf)) != -1) {
                bufferedWriter.write(buf, 0, len);
            }
            bufferedWriter.flush();
        } catch (IOException e) {
            e.printStackTrace();
//            LOGGER.error(MessageFormat.format("写入文件异常: {0}", e.getMessage()), e);
        }
    }

    /**
     * 文本文件转换为指定编码的字符串
     *
     * @param file     文本文件
     * @param encoding 编码类型
     * @return 转换后的字符串
     * @throws IOException
     */
    public static String file2String(File file, String encoding) {
        StringWriter writer = new StringWriter();
        try (InputStreamReader reader = new InputStreamReader(new FileInputStream(file), encoding)) {
            //将输入流写入输出流
            char[] buffer = new char[DEFAULT_BUFFER_SIZE];
            int n = 0;
            while (-1 != (n = reader.read(buffer))) {
                writer.write(buffer, 0, n);
            }
        } catch (Exception e) {
            e.printStackTrace();
//            LOGGER.error(MessageFormat.format("转换文件异常: {0}", e.getMessage()), e);
            return null;
        }
        //返回转换结果
        if (writer != null)
            return writer.toString();
        else return null;
    }

    /**
     * 将存放在sourceFilePath目录下的源文件，打包成fileName名称的zip文件，并存放到zipFilePath路径下
     *
     * @param filePath :待压缩的文件路径
     * @param outPath  :压缩后存放路径
     * @param
     * @return
     */
    public static void compressFile(String filePath, String outPath) {
        File file = new File(filePath);
        //输出
        File outfile = new File(outPath);
        ZipEntry ze = null;
        try (FileInputStream fis = new FileInputStream(file);
             BufferedInputStream bin = new BufferedInputStream(fis);
             DataInputStream dis = new DataInputStream(bin);
             FileOutputStream fos = new FileOutputStream(outfile);
             BufferedOutputStream bos = new BufferedOutputStream(fos, 1024);
             ZipOutputStream zos = new ZipOutputStream(bos)) {
            ze = new ZipEntry(file.getName()); //实体ZipEntry保存
            zos.putNextEntry(ze);
            int len = 0;//临时文件
            byte[] bts = new byte[DEFAULT_BUFFER_SIZE]; //读取缓冲
            while ((len = dis.read(bts)) != -1) { //每次读取1024个字节
//                LOGGER.info(String.valueOf(len));
                zos.write(bts, 0, len); //每次写len长度数据，最后前一次都是1024，最后一次len长度
            }
//            LOGGER.info("压缩文件成功");
        } catch (Exception e) {
            e.printStackTrace();
//            LOGGER.error(MessageFormat.format("压缩文件异常: {0}", e.getMessage()), e);
        }
    }


    /**
     * 解压文件
     *
     * @param sourcePath 源zip路径
     * @param targetPath 输出路径(文件夹路径)
     * @return
     */
    public static void decompressFile(String sourcePath, String targetPath) {
        try (FileInputStream fis = new FileInputStream(sourcePath);
             ZipInputStream zis = new ZipInputStream(fis);
             BufferedInputStream bis = new BufferedInputStream(zis)) {

            ZipEntry entry;

            while ((entry = zis.getNextEntry()) != null && !entry.isDirectory()) {
                File file = new File(targetPath, entry.getName());

                if (!file.exists()) {
                    (new File(file.getParent())).mkdirs();
                }

                try (FileOutputStream fos = new FileOutputStream(file);
                     BufferedOutputStream bos = new BufferedOutputStream(fos)) {
                    int b;

                    while ((b = bis.read()) != -1) {
                        bos.write(b);
                    }
                } catch (IOException e) {
                    throw e;
                }

//                LOGGER.info("{} -> 解压成功", file);
            }
        } catch (IOException e) {
            e.printStackTrace();
//            LOGGER.error(MessageFormat.format("解压文件异常 -> {0}", e.getMessage()), e);
        }
    }

    /**
     * 获取文件名
     *
     * @param path 路径
     */
    public static List<String> getFileName(String path) {
        List<String> list = new ArrayList<>();
        File file = new File(path);
        if (file.exists()) {
            File f[] = file.listFiles();
            for (int i = 0; i < f.length; i++) {
                File fs = f[i];
                if (!fs.isDirectory()) {
                    list.add(fs.getName());
                }
            }
        }
        return list;
    }

    /**
     * 根据文件地址将文件转成二进制<br>
     * <p>
     * @param filePath 文件路径
     * @return 返回文件二进制信息
     */
    public static byte[] fileToByte(String filePath){
        File file = new File(filePath);
        byte[] buffer = null;
        try {
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] b = new byte[1024];
            int n;
            while ((n = fis.read(b)) != -1){
                bos.write(b, 0, n);
            }
            fis.close();
            bos.close();
            buffer = bos.toByteArray();
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }
        return buffer;
    }

    /**
     * 保存文件的二进制数据到指定路径下，并根据文件名进行保存<br>
     * <p>
     * @param bfile 需要转换成文件的byte数组
     * @param filePath  生成的文件保存路径
     * @param fileName  生成文件后保存的名称如test.pdf，test.jpg等
     * @return 返回内容描述
     */
    public static Boolean saveFileToPath(byte[] bfile, String filePath, String fileName) {
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file;
        try {
            File dir = new File(filePath);
            boolean isDir = dir.isDirectory();
            // 目录不存在则先建目录
            if (!isDir) {
                try {
                    dir.mkdirs();
                } catch (Exception e) {
                    e.printStackTrace();
//                    LOGGER.error("创建目录失败,原因: ", e);
                }
            }
            file = new File(filePath + File.separator + fileName);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(bfile);
            if (fos.getFD().valid() == true) {
//                LOGGER.info("文件保存成功");
                return true;
            } else {
//                LOGGER.info("文件保存失败");
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
//            LOGGER.error("文件输出到指定路径失败,原因: ", e);
            return false;
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e1) {
//                    LOGGER.error("BufferedOutputStream关闭失败,原因:", e1);
                    e1.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e1) {
//                    LOGGER.error("FileOutputStream关闭失败,原因:", e1);
                    e1.printStackTrace();
                }
            }
        }
    }

    /**
     * 根据文件路径获取文件名<br>
     * <p>
     * @param filePath 文件路径
     * @return 返回内容描述
     */
    public static String getFileNameByFilePath(String filePath){
        String fileName = null;
        String[] split = filePath.split("/");
        if(split.length > 0) {
            fileName = split[split.length - 1];
        }
        return fileName;
    }

    /**
     * 下载图片
     *
     * @param fileName : 文件名
     * @param response :
     * @return: void
     * @date : 2020/10/9 10:4
     */
    @SneakyThrows(Exception.class)
    public static Boolean downloadImg(String fileUrl, String fileName, HttpServletResponse response) {
        boolean result = true;
        try {
//            String a = "D:" + "/" + fileName;
//            System.out.println(a);
//            byte[] bytes = FileUtil.getBytesByFile(a);
            byte[] bytes = FileUtil.getBytesByFile(fileUrl + "/" + fileName);
            int len = 0;
            response.reset(); // 非常重要
            // 纯下载方式
            response.setContentType("application/json;charset=utf-8");
            response.addHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
            response.addHeader("Content-Length", "" + bytes.length);
            OutputStream out = response.getOutputStream();
            out.write(bytes);
            out.flush();
            out.close();
        } catch (Exception e) {
            result = false;
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 根据文件完整路径、文件名获取文件所在路径<br>
     * </p>
     * @param complatePath 文件完整路径
     * @param fileName 文件名
     * @return 返回内容描述
     */
    public static String getFilePathByComplatePath(String complatePath, String fileName){
        String filePath = null;
        String[] split1 = complatePath.split(fileName);
        if(split1.length > 0) {
            filePath = split1[0];
            if(!"dev".equals(System.getProperty("spring.profiles.active")) && !filePath.startsWith("/")) {
                filePath = "/" + filePath;
            }
        }
        return filePath;
    }
}